﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using SchEdu.Framework.Logging;
using SchEdu.Framework.Validators;
using SchEdu.Framework.DataModel;

namespace SchEdu.Framework.Win
{

    public partial class GanttGrid : UserControl
    {
        GanttGridType ganttGridType;
        int ColumnsPerPage = 100;
        int RowsPerPage = 100;

        private Logger logger = new Logger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.ToString());

        protected Logger Logger
        {
            get { return logger; }
            set { logger = value; }
        }

        SchEduData schEduData;
        SchEduDataSet.SolutionRow solution;
        AllocationList allocations;
        XBarElementCollection xBarElements;
        int startColumn = 0;
        int startRow = 0;
        int maxColumns;
        int maxRows;
        float cellWidth = 70;
        float cellHeight = 20;

        public GanttGrid()
        {
            InitializeComponent();
        }

        public void DisplayChart(GanttGridType ganttGridType, SchEduData schEduData, SchEduDataSet.SolutionRow solution)
        {
            this.ganttGridType = ganttGridType;
            this.schEduData = schEduData;
            this.solution = solution;

            ValidateData();

            this.SuspendLayout();

            allocations = new AllocationList(solution.GetAllocationRows());
            xBarElements = new XBarElementCollection();

            if (ganttGridType == GanttGridType.Order)
            {
                foreach (SchEduDataSet.OrderRow order in schEduData.Order)
                {
                    XBarElement xBarElement = null;
                    xBarElement = new XBarElement(order.Guid, order.OrderNo);
                    xBarElements.Add(xBarElement);
                }
            }
            else
            {
                foreach (SchEduDataSet.MachineRow machine in schEduData.Machine)
                {
                    XBarElement xBarElement = null;
                    xBarElement = new XBarElement(machine.Guid,machine.Name);
                    xBarElements.Add(xBarElement);
                }
            }

            maxColumns = allocations.GetMakespan();
            maxRows = xBarElements.Count;

            DisplayPage();

            this.ResumeLayout(false);
            this.PerformLayout();
        }

        private void DisplayPage()
        {
            int columns = ColumnsPerPage;
            int rows = RowsPerPage;
            panel.AllowDrop = true;
            panel.Controls.Clear();
            panel.ColumnCount = columns + 1;
            panel.RowCount = rows + 1;
            panel.RowStyles.Clear();
            panel.ColumnStyles.Clear();
            for (int i = 0; i < panel.RowCount; i++)
            {
                panel.RowStyles.Add(new RowStyle(SizeType.Absolute,cellHeight));
            }

            for (int i = 0; i < panel.ColumnCount; i++)
            {
                panel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, cellWidth));
            }

            GanttGridLabel label = new GanttGridLabel();
            label.BackColor = Color.LightGray;
            label.TextAlign = ContentAlignment.MiddleCenter;
            panel.Controls.Add(label, 0, 0);
            label.Dock = DockStyle.Fill;
            label.Margin = new Padding(0);

            for (int i = 1; i < panel.ColumnCount; i++)
            {
                label = new GanttGridLabel();
                label.BackColor = Color.LightGray;
                label.Text = String.Format("T({0})", startColumn + i - 1);
                label.TextAlign = ContentAlignment.MiddleCenter;
                label.Dock = DockStyle.Fill;
                label.Margin = new Padding(0);
                panel.Controls.Add(label, i, 0);
            }


            for (int i = startRow; i < Math.Min(xBarElements.Count, startRow+RowsPerPage); i++)
            {
                label = new GanttGridLabel();
                label.BackColor = Color.LightGray;
                label.Text = xBarElements[i].Label;
                label.TextAlign = ContentAlignment.MiddleCenter;
                label.Dock = DockStyle.Fill;
                label.Margin = new Padding(0);
                panel.Controls.Add(label, 0, i - startRow + 1);
            }

            foreach (SchEduDataSet.AllocationRow allocation in allocations)
            {

                int row;
                if (ganttGridType == GanttGridType.Order)
                {
                    row = xBarElements.IndexOf(allocation.OrderGuid);
                }
                else
                {
                    row = xBarElements.IndexOf(allocation.MachineGuid);
                }
                if (row == -1 || row < startRow || row > startRow + RowsPerPage)
                {
                    continue;
                }
                if (allocation.EndDate < startColumn || allocation.StartDate >= startColumn + ColumnsPerPage)
                {
                    continue;
                }

                label = new GanttGridLabel();
                label.Allocation = allocation;
                if (ganttGridType == GanttGridType.Order)
                {
                    label.Text = String.Format("{0}", allocation.Machine);
                }
                else
                {
                    label.Text = String.Format("{0}-{1}", allocation.OrderNo, allocation.OperationNo);
                }

                int col;
                if (allocation.StartDate < startColumn)
                {
                    col = 1;
                }
                else
                {
                    col = (allocation.StartDate % ColumnsPerPage) + 1;
                }

                int columnSpan;

                if (allocation.StartDate < startColumn)
                {
                    columnSpan = allocation.EndDate - startColumn+1;
                }
                else
                if (allocation.EndDate > startColumn + ColumnsPerPage - 1)
                {
                    columnSpan = startColumn + ColumnsPerPage - allocation.StartDate;
                }
                else
                {
                    columnSpan = allocation.ProcessingTime;
                }
                row = row + 1;
                label.Dock = DockStyle.Fill;
                label.TextAlign = ContentAlignment.MiddleCenter;
                label.Margin = new Padding(0);
                try
                {
                    Color c = ColorTranslator.FromHtml(allocation.Color);
                    label.BackColor = c;
                }
                catch (Exception)
                {
                }
                panel.Controls.Add(label, col, row);
                panel.SetColumnSpan(label,columnSpan);
            }
        }

        private void ValidateData()
        {
            IValidator validator = new AllocationEndDateValidator(schEduData, solution);
            validator.Validate();
            validator = new AllocationStartDateValidator(schEduData, solution);
            validator.Validate();
            validator = new AllocationProcessingTimeValidator(schEduData, solution);
            validator.Validate();
        }

        private void panel_DragEnter(object sender, DragEventArgs e)
        {
            e.Effect = DragDropEffects.Move;
        }

        private void rightButton_Click(object sender, EventArgs e)
        {
            if (startColumn + ColumnsPerPage > maxColumns)
            {
                return;
            }
            startColumn += ColumnsPerPage;
            DisplayPage();
        }

        private void leftButton_Click(object sender, EventArgs e)
        {
            if (startColumn - ColumnsPerPage < 0)
            {
                return;
            }
            startColumn -= ColumnsPerPage;
            DisplayPage();
        }

        private void upButton_Click(object sender, EventArgs e)
        {
            if (startRow - RowsPerPage < 0)
            {
                return;
            }
            startRow -= RowsPerPage;
            DisplayPage();
        }

        private void downButton_Click(object sender, EventArgs e)
        {
            if (startRow + RowsPerPage > maxRows)
            {
                return;
            }
            startRow += RowsPerPage;
            DisplayPage();
        }

        private void zoomOutButton_Click(object sender, EventArgs e)
        {
            cellWidth = cellWidth * 0.9f;
            cellHeight = cellHeight * 0.9f;
            DisplayPage();
        }

        private void zoomInButton_Click(object sender, EventArgs e)
        {
            cellWidth = cellWidth * 1.1f;
            cellHeight = cellHeight * 1.1f;
            DisplayPage();
        }

    }

    public enum GanttGridType
    {
        Order,
        Machine
    }
    public class GanttGridLabel : System.Windows.Forms.Label
    {
        SchEduDataSet.AllocationRow allocation = null;

        public SchEduDataSet.AllocationRow Allocation
        {
            get { return allocation; }
            set { allocation = value; }
        }
        protected override void OnMouseDown(MouseEventArgs e)
        {
            if (allocation == null)
            {
                base.OnMouseMove(e);
                return;
            }
            DoDragDrop(allocation, DragDropEffects.Move);
        }
    }

    public class XBarElement
    {

        string label = string.Empty;

        public string Label
        {
            get { return label; }
        }

        System.Guid guid;

        public System.Guid Guid
        {
          get { return guid; }
        }


        public XBarElement(System.Guid guid, string label)
        {
            this.label = label;
            this.guid = guid;
        }

        
    }

    public class XBarElementCollection : List<XBarElement>
    {
        public int IndexOf(System.Guid guid)
        {
            for (int index = 0; index < this.Count; index++)
            {
                if (this[index].Guid == guid)
                {
                    return index;
                }
            }
            return -1;
        }
    }

    public class GanttTable : TableLayoutPanel
    {
        public GanttTable()
        {
            this.DoubleBuffered = true;
        }
    }
}
